package meshToSolid;

import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import simpleGeom.HasPos3D;
import simpleGeom.Vec3D;

public class STLWriter {
	/**
	 * A simple, but flexible and memory efficient exporter for binary STL files.
	 * Custom color support is implemented via the STLcolorModel interface and the
	 * exporter comes with the 2 most common format variations defined by the
	 * DEFAULT and MATERIALISE constants.
	 * 
	 * The minimal design of this exporter means it does not build an extra list of
	 * faces in RAM and so is able to easily export models with millions of faces.
	 * 
	 * http://en.wikipedia.org/wiki/STL_(file_format)
	 * 
	 * @author kschmidt
	 * 
	 */
	

	

		protected DataOutputStream ds;

		protected HasPos3D scale = new Vec3D(1, 1, 1);

		protected boolean useInvertedNormals = false;

		protected byte[] buf = new byte[4];

		

		public STLWriter() {
		
		}

		

		public void beginSave(String fn, int numFaces) {
			try {
				ds = new DataOutputStream(new FileOutputStream(fn));
				writeHeader(numFaces);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		public void endSave() {
			try {
				ds.flush();
				ds.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		public void face(HasPos3D a, HasPos3D b, HasPos3D c) {
			face(a, b, c, 0);
		}

		public void face(HasPos3D a, HasPos3D b, HasPos3D c, int rgb) {
			try {
				// normal
				
				//Vec3D normal = b.sub(a).cross(c.sub(a)).normalize();
				Vec3D normal=Vec3D.getNormal(a, b, c);
				if (useInvertedNormals) {
					normal.invert();
				}
				writeVector(normal);
				// vertices
				writeVector(a);
				writeVector(b);
				writeVector(c);
				// vertex attrib (color)
				
				writeShort(0);
				
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		private final void prepareBuffer(int a) {
			buf[3] = (byte) (a >>> 24);
			buf[2] = (byte) (a >> 16 & 0xff);
			buf[1] = (byte) (a >> 8 & 0xff);
			buf[0] = (byte) (a & 0xff);
		}

		public void setScale(float s) {
			scale.setPosition(s, s, s);
		}

		public void setScale(Vec3D s) {
			scale.setX(s.getX());
			scale.setY(s.getY());
			scale.setZ(s.getZ());
		}

		public void useInvertedNormals(boolean state) {
			useInvertedNormals = state;
		}

		protected void writeFloat(float a) throws IOException {
			prepareBuffer(Float.floatToRawIntBits(a));
			ds.write(buf, 0, 4);
		}

		protected void writeHeader(int num) throws IOException {
			byte[] header = new byte[80];
			ds.write(header, 0, 80);
			writeInt(num);
		}

		protected void writeInt(int a) throws IOException {
			prepareBuffer(a);
			ds.write(buf, 0, 4);
		}

		protected void writeShort(int a) throws IOException {
			ds.writeByte(a & 0xff);
			ds.writeByte(a >> 8 & 0xff);
		}

		protected void writeVector(HasPos3D v) {
			try {
				writeFloat(v.getX() * scale.getX());
				writeFloat(v.getY() * scale.getY());
				writeFloat(v.getZ() * scale.getZ());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

